import pymongo
import datetime
import socket
import threading
import SocketServer
import time


# Port 0 means to select an arbitrary unused port
HOST, PORT = "175.159.24.156", 4009

# for storing push list
pushdict = {}

def connmongo():
    from pymongo import Connection
    conn = Connection('localhost', 27017)
    db = conn.aa
    return db
#end connmongo

#Async Server
class ThreadedTCPRequestHandler(SocketServer.StreamRequestHandler):

    # fromat : push friend tom
    def push_friend(self, src, pushto):
        for to in pushto:
            if(pushdict.has_key(to)):
                msg = "push friend " + src + "\n"
                print msg + "to " + str(len(pushdict))
                pushdict[to].write(msg)
            #endif
        #end for
    #end push_friend

    # format : push activity jason 1234
    def push_activity(self, whom, length):
        msg = "push activity " + whom + " " + length + "\n"
        # check push destination, only those follow whom
        db = connmongo()
        users = db.user
        res = users.find({"follow" : whom })
        for t in res:
            cuid = t["uid"]
            if(pushdict.has_key(cuid)):
                print msg + "to " + str(len(pushdict))
                pushdict[cuid].write(msg)
            #end if
        #end for
        return 
    #end push_activity

    """
    # request all users in DB
    REQ: friend all
    RES: ok tom,jerry
    # get user's following list
    REQ: friend follow jason
    RES: ok tom,jerry
    # update following list for user
    REQ: friend update jason tom,jerry,ben
    RES: ok
    # get who is following user
    REQ: friend follower jason
    RES: ok tom,jerry
    """
    def handle_friend(self, args):
        ret = "ok "
        # db conn
        db = connmongo()
        users = db.user
        if (args[1] == "all"):
            ids = list(users.distinct("uid"))
            for t in ids: ret = ret + t + ','
        elif (args[1] == "follow"):
            ids = list(users.find_one({"uid" : args[2]})["follow"])
            for t in ids: ret = ret + t + ','
        elif (args[1] == "update"):
            usr = users.find_one({"uid" : args[2]})
            newfollow = args[3].split(',')
            usr["follow"] = newfollow
            users.save(usr)
            self.data = "ok"
            
            # PUSH PUSH push here
            self.push_friend(args[2], newfollow)
            
        elif (args[1] == "follower"):
            res = users.find({"follow" : args[2] })
            for t in res : ret = ret + t["uid"] + ','
        #end if

        self.data = ret.strip(',')
    #end handle_friend

    """
    # synchronize the activity with server
    REQ: activity sync jason 30
    RES: ok tom,1333174320,1333177937,1332745920,874 jerry,1333174320,1333177937,1332745920,874
    # add an activity to server
    REQ: activity add uid,epoch_beg,epoch_end,length,trace
    EXA: activity add jason,1333178959,1333178959,123,null
    RES: ok
    """
    def handle_activity(self, args):
        db = connmongo()
        acts = db.activity
        users = db.user
        ret = "ok "

        if(args[1] == "add"):
            params = args[2].split(',')
            act = {}
            act["uid"] = params[0]
            act["beg"] = datetime.datetime.fromtimestamp(int(params[1]))
            act["end"] = datetime.datetime.fromtimestamp(int(params[2]))
            act["cur"] = datetime.datetime.now()
            act["length"] = int(params[3])
            act["trace"] = ""

            print act
            acts.insert(act)

            #check for push message
            self.push_activity(params[0], params[3])
            
        elif(args[1] == "sync"):
            #1. get who user is following
            friends = users.find_one({"uid" : args[2]})["follow"]
            # plus myself
            friends.append(args[2])
            print friends
            #2. get timestamp
            syntime = datetime.datetime.now() - datetime.timedelta(days=int(args[3]))
            print syntime
            #3. find
            rs = acts.find({"uid":{"$in": friends}, "cur":{"$gt": syntime}}).sort("cur",pymongo.DESCENDING)
            for t in rs :
                stm = lambda x: str(int(time.mktime(x.timetuple())))
                tmp = t["uid"] + ',' + stm(t["beg"]) + ',' + stm(t["end"]) + ',' + stm(t["cur"]) + ',' + str(t["length"]) + ',' + t["trace"]
                ret = ret + tmp.rstrip(',') + ' '
        #end if
        self.data = ret.strip()
    #end handle_activity


    """
    #1. friend
    #2. activity
    #3. push
    #4. test
    """
    def handle(self):
        self.data = self.rfile.readline().strip()
        print "Received : " + self.data

        # a simple command parser
        args = self.data.split()

        if args[0] == "friend":
            self.handle_friend(args)
        elif args[0] == "activity":
            self.handle_activity(args)
        elif args[0] == "push":
            uid = args[1]
            print uid + "push"
            #save the socket to push list
            sock = self.request
            pushdict[uid] = self.wfile;
            self.wfile.write("ok" + "\n")
            
            #block the socket
            print "server blocked"
            sock.setblocking(1);
            sock.recv(4096)
            del pushdict[uid]
            print uid + " disconnected"
            return
        elif(args[0] == "test"):
            self.data = "ok ben,1333174320,1333177937,1332745920,874 jerry,1333174320,1333177937,1332745920,874";
        else:
            print "Invalid"
        #end if

        #write to client
        self.wfile.write(self.data)


class ThreadedTCPServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer):
    pass



if __name__ == "__main__":

    print "Welcome to Runking server. Starting..."


    server = ThreadedTCPServer((HOST, PORT), ThreadedTCPRequestHandler)

    print "Server Started"
    print "Server IP: " + HOST
    print "listening for new users..."
    # Start a thread with the server -- that thread will then start one
    # more thread for each request
    server.serve_forever()
